import numpy as np


class VecCom(object):
    """
    向量
    """
    def __init__(self, arr1, arr2):
        self.arr1 = arr1
        self.arr2 = arr2

    def inner_product_1(self):
        """
        一维数组/向量：内积/点乘：对应位置相乘，然后求和
        二维数组/矩阵：矩阵乘法运算
        """
        return np.dot(self.arr1, self.arr2)

    def inner_product_2(self):
        """
        一维数组/向量：内积/点乘
        二维数组/矩阵：矩阵乘法运算
        """
        return np.matmul(self.arr1, self.arr2)

    def hadamard_1(self):
        """
        阿达马积：对应位置的元素相乘得到新的元素
        """
        return np.multiply(self.arr1, self.arr2)

    def hadamard_2(self):
        """
        数组/向量：阿达马积：对应位置的元素相乘得到新的元素
        矩阵：矩阵乘法运算
        """
        return np.array(self.arr1) * np.array(self.arr2)

    def out_product_1(self):
        """
        向量外积
        """
        return np.outer(self.arr1, self.arr2)

    def out_product_2(self):
        """
        向量外积：张量积的一种特殊形式
        """
        return np.kron(self.arr1, self.arr2)

    def cross_product(self):
        """
        叉积：返回一个垂直这两个向量的向量
        如果是矩阵，则是矩阵的行向量或列向量之间的运算
        """
        return np.cross(self.arr1, self.arr2)

    def kronecker_product(self):
        """
        张量积
        """
        return np.kron(self.arr1, self.arr2)


class MatCom(object):
    """
    矩阵计算
    """
    def __init__(self, arr1, arr2):
        self.arr1 = np.array(arr1)
        self.arr2 = np.array(arr2)

    def hadamard_1(self):
        """
        阿达马积：对应位置的元素相乘得到新的元素
        """
        return np.multiply(self.arr1, self.arr2)

    def hadamard_2(self):
        """
        数组/向量：阿达马积：对应位置的元素相乘得到新的元素
        矩阵：矩阵乘法运算
        """
        return np.array(self.arr1) * np.array(self.arr2)

    def multiplicate_1(self):
        """
        矩阵乘法
        """
        return np.dot(self.arr1, self.arr2.T)

    def multiplicate_2(self):
        """
        矩阵乘法
        """
        return np.matmul(self.arr1, self.arr2.T)

    @staticmethod
    def mat_inverse(arr):
        """
        求解矩阵的逆
        """
        # 计算行列式的值：判断是否满秩
        det_v = np.linalg.det(arr)
        return np.linalg.inv(arr) if det_v != 0 else None


def solve_equation(a_arr, b_arr):
    """
    求方程组的解
    """
    return np.linalg.solve(a_arr, b_arr)


def get_eig(arr):
    """
    求解矩阵特征值 & 特征向量
    """
    v, vec = np.linalg.eig(np.array(arr))
    return v, vec


def run():
    """

    """
    # 向量计算
    arr1 = [1, 2, 6]
    arr2 = [-1, 3, 9]
    vec = VecCom(arr1=arr1, arr2=arr2)
    inner_1 = vec.inner_product_1()
    inner_2 = vec.inner_product_2()
    hada_1 = vec.hadamard_1()
    hada_2 = vec.hadamard_2()
    outer_1 = vec.out_product_1()
    outer_2 = vec.out_product_2()
    cross = vec.cross_product()
    kronecker = vec.kronecker_product()

    vec_info = '向量内积 dot: {}\n向量内积 matmul: {}\n向量阿达马积 multiply：{}\n' \
           '向量阿达马积 *：{}\n向量外积 outer：{}\n向量外积 张量积特殊形式：{}\n' \
           '向量叉积 cross：{}\n向量张量积：{}'.\
        format(inner_1, inner_2, hada_1, hada_2, outer_1, outer_2,
               cross, kronecker)
    print(vec_info)

    # 矩阵计算
    mat_arr1 = [[1,2,3], [4,5,6]]
    mat_arr2 = [[1,2,4], [3,6,9]]
    mat_com = MatCom(arr1=mat_arr1, arr2=mat_arr2)
    hada_1 = mat_com.hadamard_1()
    hada_2 = mat_com.hadamard_2()
    mult_1 = mat_com.multiplicate_1()
    mult_2 = mat_com.multiplicate_2()
    mat_info = '阿达马积 multiply:{}\n阿达马积 *:{}\n' \
               '矩阵乘法 dot:{}\n矩阵乘法 matmul:{}'.\
        format(hada_1, hada_2, mult_1, mult_2)
    print(mat_info)
    inv_arr = [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
    inv_mat = mat_com.mat_inverse(arr=inv_arr)
    print('逆矩阵： {}'.format(inv_mat))

    # 求解方程组
    A = np.array([[3, 1], [1, 2]])
    b = np.array([9, 8])  # 方程组右侧的值
    equation_v = solve_equation(a_arr=A, b_arr=b)
    print('方程组的解： {}'.format(equation_v))

    # 求解特征值 & 特征向量
    eig_arr = [[1, 0, 0], [0, 1, 0], [0, 3, 0]]
    eig_v, eig_vec = get_eig(arr=eig_arr)
    print('矩阵的特征值为： {}\n特征向量为： {}'.format(eig_v, eig_vec))


if __name__ == '__main__':
    run()
